/** @file

  Copyright (C) 2022 - 2023, Phytium Technology Co., Ltd. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <Uefi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>

#include "Mhu.h"

#define TICKS_PER_MS   48000

STATIC UINTN GetTicks(VOID)
{
  UINTN cntpct;

  asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct));

  return cntpct;
}

STATIC VOID MDelay(UINT32 Time)
{
  UINTN Start, End;

  Start = GetTicks();
  End = Start + Time * TICKS_PER_MS;
  while(GetTicks() <= End) {
  }
}

VOID MhuChnInit(UINT32 ChnType)
{
    UINTN Base = MHU_CONFIG_BASE;

    if(MHU_SCP_UBOOT_CHN == ChnType) {
        Base += 0x4;
    } else if (MHU_UBOOT_SCP_CHN == ChnType) {
        Base += 0xc;
    } else if (MHU_SCP_OS_CHN == ChnType) {
        Base += 0x0;
    } else if (MHU_OS_SCP_CHN == ChnType) {
        Base += 0x8;
    } else {
        //printf("init : mhu channel %d not supported.\n", ChnType);
        return;
    }

    //writel(0x1, Base);
    //writel(0x1, Base);
    MmioWrite32(Base, 0x1);

    return;
}


INT32 MhuChnMessageStart(UINT32 ChnType, UINT32 SlotId)
{
    UINTN Base = 0;
    UINT32 Val = 0;
    INT32 i;

    if(MHU_SCP_UBOOT_CHN == ChnType) {
        Base = MHU_SCP_UBOOT_BASE;
    } else if (MHU_UBOOT_SCP_CHN == ChnType) {
        Base = MHU_UBOOT_SCP_BASE;
    } else if (MHU_SCP_OS_CHN == ChnType) {
        Base = MHU_SCP_OS_BASE;
    } else if (MHU_OS_SCP_CHN == ChnType) {
        Base = MHU_OS_SCP_BASE;
    } else {
        //printf("Start : mhu channel %d not supported.\n", ChnType);
        DEBUG((EFI_D_INFO, "Start : mhu channel %d not supported.\n", ChnType));
        return -1;
    }

    /* Make sure any previous command has finished */
    for(i = 0; i < 10; i++) {
        //Val = readl(Base + MHU_STAT) & (1 << SlotId);
        Val = MmioRead32(Base + MHU_STAT) & (1 << SlotId);
        if(Val & (1 << SlotId))
            //MDelay(1);
            MDelay(1);
        else
            return 0;
    }

    //printf("scpi wait for slot %d timeout.\n", SlotId);
    DEBUG((EFI_D_INFO, "scpi wait for slot %d timeout.\n", SlotId));
    return -1;
}

INT32 MhuChnMessageSend(UINT32 ChnType, UINT32 SlotId)
{
    UINTN Base = 0;

    if(MHU_SCP_UBOOT_CHN == ChnType) {
        Base = MHU_SCP_UBOOT_BASE;
    } else if (MHU_UBOOT_SCP_CHN == ChnType) {
        Base = MHU_UBOOT_SCP_BASE;
    } else if (MHU_SCP_OS_CHN == ChnType) {
        Base = MHU_SCP_OS_BASE;
    } else if (MHU_OS_SCP_CHN == ChnType) {
        Base = MHU_OS_SCP_BASE;
    } else {
        printf("send : mhu channel %d not supported.\n", ChnType);
        return -1;
    }

    /* Send command to SCP */
    //writel(1 << SlotId, Base + MHU_SET);
    MmioWrite32(Base + MHU_SET, 1 << SlotId);

    return 0;
}


INT32 MhuChnMessageEnd(UINT32 ChnType, UINT32 SlotId)
{
    UINTN Base = 0;

    if(MHU_SCP_UBOOT_CHN == ChnType) {
        Base = MHU_SCP_UBOOT_BASE;
    } else if (MHU_UBOOT_SCP_CHN == ChnType) {
        Base = MHU_UBOOT_SCP_BASE;
    } else if (MHU_SCP_OS_CHN == ChnType) {
        Base = MHU_SCP_OS_BASE;
    } else if (MHU_OS_SCP_CHN == ChnType) {
        Base = MHU_OS_SCP_BASE;
    } else {
        printf("send : mhu channel %d not supported.\n", ChnType);
        return -1;
    }

    /*
     * Clear any Response we got by writing one in the relevant slot bit to
     * the CLEAR register
     */
    MmioWrite32(Base + MHU_CLEAR, 1 << SlotId);
    return 0;
}

INT32 MhuChnMessageWait(UINT32 ChnType, UINT32 SlotId)
{
    INT32 i = 0;
    UINTN Base = 0;
    /* Wait for Response from SCP */
    UINT32 Response;

    if(MHU_SCP_UBOOT_CHN == ChnType) {
        Base = MHU_SCP_UBOOT_BASE;
    } else if (MHU_UBOOT_SCP_CHN == ChnType) {
        Base = MHU_UBOOT_SCP_BASE;
    } else {
        printf("wait : mhu channel %d not supported.\n", ChnType);
        return -1;
    }

    for(i = 0; i < 100; i++) {
        Response = MmioRead32(Base + MHU_STAT) & (1 << SlotId);
        if(1 != (Response & (1 << SlotId)))
            MDelay(1);
        else
            return 0;
    }

    printf("wait for scp Response timeout.\n");
    return -1;
}

